from PyQt5.QtWidgets import QDialog
from Processor.threshold.threshold_design import Ui_ThresholdDialog

import time
import cv2
import Processor.Converter as Converter


class ThresholdDialog(QDialog, Ui_ThresholdDialog):
    firstUse = True
    thresholdType = ()  # 阈值类型列表
    adaptiveMethod = None  # 自适应阈值计算方法列表
    mat = None  # 原始灰度图数据（即第一次计算阈值前的数据。每一次阈值计算以这个值为基础）
    layer = None  # 当前操作的图层

    def __init__(self, parent):
        super().__init__(parent)
        self.setupUi(self)
        self.adaptive_arg_panel.hide()
        self.initUI(parent)
        # self.show()

    def initUI(self, parent):

        self.setWindowTitle('阈值控制器')
        # 定位
        pos = parent.geometry()
        self.move(pos.width() / 10, pos.height() - self.height() - pos.height() / 20)
        #       信号
        # 确定
        self.DialogButtonBox.accepted.connect(self.accept)
        # 阈值类型
        self.comboBox_threshold_method.currentIndexChanged.connect(self.updateSlot)
        self.thresholdType = (
            cv2.THRESH_BINARY, cv2.THRESH_BINARY_INV, cv2.THRESH_TRUNC, cv2.THRESH_TOZERO, cv2.THRESH_TOZERO_INV)
        # 自适应阈值
        self.comboBox_adaptiveMethod.currentIndexChanged.connect(self.updateSlot)
        self.adaptiveMethod = (cv2.ADAPTIVE_THRESH_MEAN_C, cv2.ADAPTIVE_THRESH_GAUSSIAN_C)
        self.radioButton_adaptive.toggled.connect(self.radioButton_adaptive_toggledSlot)
        # 阈值
        self.spinBox_threshold.valueChanged.connect(self.updateSlot)
        # 最大值
        self.spinBox_maxval.valueChanged.connect(self.updateSlot)
        # 步进块
        self.spinBox_blockSize.valueChanged.connect(self.updateSlot)
        self.spinBox_c.valueChanged.connect(self.updateSlot)

    def updateSlot(self):
        if self.firstUse:
            self.firstUse = False

        maxval = self.spinBox_maxval.value()
        thresholdType = self.thresholdType[self.comboBox_threshold_method.currentIndex()]
        if self.radioButton_adaptive.isChecked():
            adaptiveMethod = self.adaptiveMethod[self.comboBox_adaptiveMethod.currentIndex()]
            blockSize = self.spinBox_blockSize.value()
            c = self.spinBox_c.value()
            self.__adaptiveThreshold(maxval, adaptiveMethod, thresholdType, blockSize, c)
        else:
            threshold = self.spinBox_threshold.value()
            self.__threshold(threshold, maxval, thresholdType)

    def radioButton_adaptive_toggledSlot(self):
        if self.radioButton_adaptive.isChecked():
            self.adaptive_arg_panel.show()
            print('转换自适应阈值')
        else:
            self.adaptive_arg_panel.hide()
            print('关闭自适应阈值')
        self.updateSlot()
        self.update()

    def accept(self):
        if self.firstUse:
            self.updateSlot()
        QDialog.accept(self)

    def __threshold(self, thresh=127, maxval=255, ty=cv2.THRESH_BINARY):
        """
        :param mat:
        :param thresh:
        :param maxval:
        :param ty:
        • cv2.THRESH_BINARY
        • cv2.THRESH_BINARY_INV
        • cv2.THRESH_TRUNC
        • cv2.THRESH_TOZERO
        • cv2.THRESH_TOZERO_INV
        :return:
        """
        start = time.perf_counter()
        mat = self.mat
        ret, thresh = cv2.threshold(mat, thresh, maxval, ty)
        mat = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGRA)
        image = Converter.Numpy2QImage(mat)
        end = time.perf_counter()
        print('threshold', '耗时：', end - start)
        self.layer.updatePixmap(image)

    def __adaptiveThreshold(self, maxval=255, adaptiveMethod=cv2.ADAPTIVE_THRESH_MEAN_C,
                            thresholdType=cv2.THRESH_BINARY, blockSize=11, c=1):
        """
        自适应阈值
        :param image:
        :param maxval: 高于或低于阈值时，设为此值
        :param adaptiveMethod: 自适应方法
        ·cv2.ADPTIVE_THRESH_MEAN_C：阈值取自相邻区域的平均值
    –  ·cv2.ADPTIVE_THRESH_GAUSSIAN_C，阈值取值相邻区域的加权和，权重为一个高斯窗口。
        :param thresholdType: 阈值类型,支持binary和binary-inv方法
        :param blockSize: 领域大小
        :param c:修正常数
        :return:
        """
        start = time.perf_counter()
        mat = self.mat
        if blockSize % 2 != 1:    # 必须为奇数
            blockSize = blockSize + 1
        if thresholdType != cv2.THRESH_BINARY:
            thresholdType = cv2.THRESH_BINARY_INV
        mat = cv2.adaptiveThreshold(mat, maxval, adaptiveMethod, thresholdType, blockSize, c)
        mat = cv2.cvtColor(mat, cv2.COLOR_GRAY2BGRA)
        image = Converter.Numpy2QImage(mat)
        end = time.perf_counter()
        print('adaptiveThreshold', '耗时：', end - start)
        self.layer.updatePixmap(image)


def newThreshold(window):
    """
    :param window: 主窗体
    :return:
    """
    layer = window.currentLayer
    if layer:
        image = layer.image  # 当前图层QImage句柄
        mat = Converter.QImage2Numpy(image)
        controller = ThresholdDialog(window)
        mat = cv2.cvtColor(mat, cv2.COLOR_RGBA2GRAY)
        controller.mat = mat
        controller.layer = layer
        if controller.exec_():
            pass
